package lesson4.example4;

import com.classloading.utils.JavaCompilerUtil;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

public class TestJavassist extends ClassLoader{

	public static String path = JavaCompilerUtil.path +"/bytecode-examples/bytecode-example-4-02/src/main/java/";
	public static String destpath = JavaCompilerUtil.path +"/bytecode-examples/bytecode-example-4-02/output";
	
	public static void main(String args[]) throws Exception {
		JavaCompilerUtil.compile(path+"/lesson4/example4/TestDemo.java", destpath);
		testUpdateMethodByJavassist();
//		testAddMethodByJavassist();
//		JavaCompilerUtil.decompile(destpath+"/lesson4/example4/TestDemo.class");
		Thread.sleep(2000L);
		JavaCompilerUtil.run(new String[] { "java", "-cp", destpath, "lesson4.example4.TestDemo" });
	}
	
	// ClassPool是一个容器，存储着一系列的CtClass对象
	// CtClass表示编译时的类，在CtClass中有方法addMethod()、addField()方法可新增方法、字段信息，writeFile()方法可输出字节码文件
	// CtMethod与CtField分别表示编译时的方法和字段，对于CtMethod来说，可通过insertBefore()、insertAfter()、
	// setBody()、addCatch()等方法增强原有方法的逻辑
	public static void testUpdateMethodByJavassist() throws Exception {
		ClassPool pool = ClassPool.getDefault();
		// 为指定路径下的二进制字节码文件做增强
		pool.insertClassPath(destpath+"/lesson4/example4/TestDemo.class");

        CtClass ctClass = pool.get("lesson4.example4.TestDemo");
        CtMethod method = ctClass.getDeclaredMethod("foo");
        
        /*
	        Javassist框架通过编写源代码的方式实现字节码增强，其中Javassist定义了以$开头的特殊标识符，常用的如下：
	        $0、$1等表示方法参数，$0表示this
	        $args表示方法参数数组，类型为Object[]
	        $$表示所有参数
	        $_表示返回值
	        $e表示抛出的异常
	        ...
       */
        method.insertBefore("System.out.println(\"param 1:\"+$0+\",param 2:\"+$1);");
        method.insertAfter("System.out.println(\"return:\"+$_);");
        
        ctClass.writeFile(destpath);
	}
	
	public static void testAddMethodByJavassist() throws Exception {
		ClassPool pool = ClassPool.getDefault();
		pool.insertClassPath(destpath + "/lesson4/example4/TestDemo.class");
		CtClass ctClass = pool.get("lesson4.example4.TestDemo");

		CtMethod method = new CtMethod(CtClass.intType, "foo1", new CtClass[] { CtClass.intType, CtClass.intType },ctClass);
		method.setBody("return 2;");
		ctClass.addMethod(method);

		ctClass.writeFile(destpath);
	}
	
}
